﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Basmus.Tests
{
    public static class TypeHelper
    {
        //value type to add here
        public static IEnumerable<Type> ValueTypes()
        {
            yield return typeof(int);
            yield return typeof (bool);
            yield return typeof (Guid);
            yield return typeof (TestEnum);
        }

        //reference type to add here
        public static IEnumerable<Type> ReferenceTypes()
        {
            yield return typeof (string);
        }

        ///collection generic type definition to add here
        public static IEnumerable<Type> CollectionGenericTypeDefinitions()
        {
            yield return typeof(IList<>);
            yield return typeof(List<>);
            yield return typeof(IEnumerable<>);
        }

        public static IEnumerable<Type> NullableTypes()
        {
            return ValueTypes().MakeGenericTypesForDefinition(typeof (Nullable<>));
        }

        public static IEnumerable<Type> EveryPossibleElementTypes()
        {
            return ValueTypes()
                .Concat(ReferenceTypes())
                .Concat(NullableTypes());
        }

        public static IEnumerable<Type> EveryPossibleContainerType()
        {
            var collectionGenericTypes = EveryPossibleElementTypes()
                .SelectMany(x => CollectionGenericTypeDefinitions().MakeGenericTypesForArguments(x));
            var arryTypes = EveryPossibleElementTypes()
                .Select(x => x.MakeArrayType());
            var allTypes = EveryPossibleElementTypes()
                .Concat(collectionGenericTypes)
                .Concat(arryTypes);
            return allTypes;
        }


        public static IEnumerable<Type> MakeGenericTypesForArguments(this IEnumerable<Type> genericTypeDefinitions, Type argumentType)
        {
            return genericTypeDefinitions.Select(x => x.MakeGenericType(argumentType));
        }
        public static IEnumerable<Type> MakeGenericTypesForDefinition(this IEnumerable<Type> typeArguments, Type genericTypeDefinition)
        {
            return typeArguments.Select(x => genericTypeDefinition.MakeGenericType(x));
        }

        //return every possible pairs: item1 - elementType, item2 - containerType
        public static IEnumerable<Tuple<Type, Type>> GetAllPairs()
        {
            return EveryPossibleElementTypes()
                .Select(x => new
                                 {
                                     elementType = x,
                                     containerTypes = EveryPossibleContainerType()
                                 })
                .SelectMany(x => x.containerTypes.Select(y => new Tuple<Type, Type>(x.elementType, y)));
        }


    }
}
